package auth

import (
	auth_dto "auth-service/internal/dto/authDto"
	"auth-service/internal/global"
	"auth-service/internal/model"
	"errors"
	"fmt"
	"github.com/danfwing/sd-project/pkg/base"
	"github.com/danfwing/sd-project/pkg/utils"
	"time"
)

type AuthService struct{}

// Login 用户登录
func (s *AuthService) Login(req *auth_dto.LoginRequest, ip string) (auth_dto.LoginResponse, error) {
	var account model.Account
	var resp auth_dto.LoginResponse
	var has bool
	var err error
	var loginType string

	// 根据用户名或手机号查找账户
	if req.Username != "" {
		has, err = global.GDB.Where("username = ?", req.Username).Get(&account)
		loginType = "username"
	} else if req.Phone != "" {
		has, err = global.GDB.Where("phone = ?", req.Phone).Get(&account)
		loginType = "phone"
	} else {
		return resp, errors.New("username or phone is required")
	}

	if err != nil {
		return resp, fmt.Errorf("get account error: %v", err)
	}
	if !has {
		return resp, errors.New("account not found")
	}

	if !utils.CheckPasswordHash(req.Password, account.Password) {
		return resp, errors.New("invalid password")
	}

	if account.Status != 1 {
		return resp, errors.New("account is disabled")
	}

	// 更新登录信息
	account.LastLoginAt = time.Now().Unix()
	account.LastLoginIP = ip
	account.LoginType = loginType
	_, err = global.GDB.ID(account.Id).Cols("last_login_at", "last_login_ip", "login_type").Update(&account)
	if err != nil {
		return resp, fmt.Errorf("update login info error: %v", err)
	}
	//获取当前用户
	var u model.User
	global.GDB.Where("code = ?", account.UserCode).Get(&u)
	//获取role
	var roles []string
	global.GDB.Table(&model.UserRole{}).Where("user_code = ?", account.UserCode).Cols("role_code").Find(&roles)
	// 生成Token
	token, err := utils.GenerateTokenPair(u.Code, account.Username, roles)
	if err != nil {
		return resp, fmt.Errorf("generate token error: %v", err)
	}

	resp = auth_dto.LoginResponse{
		UserCode:     account.UserCode,
		Username:     account.Username,
		Phone:        account.Phone,
		Token:        token.AccessToken,
		RefreshToken: token.RefreshToken,
		LoginType:    loginType,
	}
	return resp, nil
}

// Register 创建认证账户
func (s *AuthService) Register(req *auth_dto.RegisterRequest) (string, error) {
	// 检查用户名是否已存在
	exist, err := global.GDB.Where("username = ?", req.Username).Exist(&model.Account{})
	if err != nil {
		return "", fmt.Errorf("check username exist error: %v", err)
	}
	if exist {
		return "", errors.New("username already exists")
	}

	// 如果提供了手机号，检查手机号是否已存在
	if req.Phone != "" {
		exist, err = global.GDB.Where("phone = ?", req.Phone).Exist(&model.Account{})
		if err != nil {
			return "", fmt.Errorf("check phone exist error: %v", err)
		}
		if exist {
			return "", errors.New("phone already exists")
		}
	}
	//是不是需要查询到user?

	// 创建认证账户
	hashedPassword, err := utils.HashPassword(req.Password)
	if err != nil {
		return "", fmt.Errorf("hash password error: %v", err)
	}

	// 创建用户
	session := global.GDB.NewSession()
	defer session.Close()
	session.Begin()

	var u model.User
	u = model.User{
		Model:    base.Model{},
		Username: req.Username,
		Password: hashedPassword,
		Email:    "",
		Phone:    req.Phone,
		Nickname: req.Username,
		Avatar:   "",
		Status:   1,
		Roles:    nil,
	}

	u.Model = *utils.NewModel("")

	_, err = session.Insert(&u)
	if err != nil {
		session.Rollback()
		return "", fmt.Errorf("insert user error: %v", err)
	}

	var u_role model.UserRole
	u_role = model.UserRole{
		UserCode: u.Code,
		RoleCode: "user",
	}

	_, err = session.Insert(&u_role)
	if err != nil {
		session.Rollback()
		return "", fmt.Errorf("insert user role error: %v", err)
	}

	account := &model.Account{
		Username: req.Username,
		Phone:    req.Phone,
		UserCode: u.Code,
		Password: hashedPassword,
		Status:   1,
	}
	account.Model = *utils.NewModel("")
	_, err = session.Insert(account)
	if err != nil {
		session.Rollback()
		return "", fmt.Errorf("insert account error: %v", err)
	}
	if err := session.Commit(); err != nil {
		session.Rollback()
		return "", fmt.Errorf("commit transaction error: %v", err)
	}
	return account.UserCode, nil
}

// BindPhone 绑定手机号
func (s *AuthService) BindPhone(userCode int64, req *auth_dto.BindPhoneRequest) error {
	var account model.Account
	has, err := global.GDB.Where("user_code = ?", userCode).Get(&account)
	if err != nil {
		return fmt.Errorf("get account error: %v", err)
	}
	if !has {
		return errors.New("account not found")
	}

	// 验证密码
	if !utils.CheckPasswordHash(req.Password, account.Password) {
		return errors.New("invalid password")
	}

	// 检查手机号是否已被其他账户使用
	exist, err := global.GDB.Where("phone = ? AND user_code != ?", req.Phone, userCode).Exist(&model.Account{})
	if err != nil {
		return fmt.Errorf("check phone exist error: %v", err)
	}
	if exist {
		return errors.New("phone already exists")
	}

	account.Phone = req.Phone
	_, err = global.GDB.ID(account.Id).Cols("phone").Update(&account)
	if err != nil {
		return fmt.Errorf("update phone error: %v", err)
	}

	return nil
}

// InvalidateToken 使token失效
func (s *AuthService) InvalidateToken(userCode int64) error {
	var account model.Account
	has, err := global.GDB.Where("user_code = ?", userCode).Get(&account)
	if err != nil {
		return fmt.Errorf("get account error: %v", err)
	}
	if !has {
		return errors.New("account not found")
	}

	account.TokenVersion++
	_, err = global.GDB.ID(account.Id).Cols("token_version").Update(&account)
	if err != nil {
		return fmt.Errorf("update token version error: %v", err)
	}

	return nil
}

// ChangePassword 修改密码
func (s *AuthService) ChangePassword(userID int64, req *auth_dto.ChangePasswordRequest) error {
	var account model.Account
	has, err := global.GDB.Where("user_id = ?", userID).Get(&account)
	if err != nil {
		return fmt.Errorf("get account error: %v", err)
	}
	if !has {
		return errors.New("account not found")
	}

	if !utils.CheckPasswordHash(req.OldPassword, account.Password) {
		return errors.New("invalid old password")
	}

	hashedPassword, err := utils.HashPassword(req.NewPassword)
	if err != nil {
		return fmt.Errorf("hash password error: %v", err)
	}

	account.Password = hashedPassword
	account.TokenVersion++ // 使当前token失效
	_, err = global.GDB.ID(account.Id).Update(&account)
	if err != nil {
		return fmt.Errorf("update password error: %v", err)
	}

	return nil
}
